// Unit Test for file delegates

#include "image/image.h"
#include "image/convolve.h"
#include "image/imageTransform.h"
#include "delegates/io.h"

#include "unitTest.h"

#include <fstream>

using namespace simple;

namespace simple_test{
    UTFUNC(ctor)
    {
        setDescription ("Constructor and simple accessor tests");

        Rect boundary (0, 0, 640, 480);
        Image<Pel8> byteImage3 (boundary, 
                                RectImageStorage::eQuadWordAlign);

        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("jpg");
        VERIFY (delegate != 0);

        if (delegate) {
            Image<RGB> rgb = delegate->readRGB ("test.jpg");
            Image<RGB> rgbDest;

            // Only run on right half of image
            Image<RGB> rgbWindow = rgb;
            rgbWindow.window (Rect (rgb.width()/2, 0, rgb.width()/2, rgb.height()));

            laplacian3x3<RGBPel32s>(rgbWindow, rgbDest);
            copy (rgbDest, rgbWindow);

            delegate->write ("output.jpg", rgb);

            // Unsharp mask test
            rgb = delegate->readRGB ("test.jpg");

            Image<RGB> unsharp;
            copy (rgb, unsharp);
            unsharpMask<RGBPel32s> (unsharp, 3.0);
            delegate->write ("unsharpMask.jpg", unsharp);

            // Average low-pass
            Image<RGB> rgbAverage;
            char kernel[] = {1, 1, 1, 1, 1, 1, 1, 1, 1};
            convolve<RGBPel32s>(rgb, kernel, 3, 9, rgbAverage);
            delegate->write( "Average.jpg", rgbAverage);
        
            // Thumbnails
            Image<RGB> thumb2 = thumbnail<RGBPel32s> (rgb, 2);
            delegate->write ("testthumb2.jpg", thumb2);
            Image<RGB> thumb3 = thumbnail<RGBPel32s> (rgb, 3);
            delegate->write ("testthumb3.jpg", thumb3);
            Image<RGB> thumb4 = thumbnail<RGBPel32s> (rgb, 4);
            delegate->write ("testthumb4.jpg", thumb4);
            Image<RGB> thumb8 = thumbnail<RGBPel32s> (rgb, 8);
            delegate->write ("testthumb8.jpg", thumb8);
        }


        // TIFF test

        ImageIOBase* tiffdelegate;
        Image<RGB> RGBtiff;
        tiffdelegate = ImageIODelegateList::gOnly().getDelegate ("tif");
        VERIFY (tiffdelegate != 0);
        if (tiffdelegate) {
            RGBtiff = tiffdelegate->readRGB ("saturn.tif");

            delegate->write ("tif.jpg", RGBtiff);
            tiffdelegate->write ("tif.tif", RGBtiff); // Lossless

            Image<RGB> lossless;
            tiffdelegate->read ("tif.tif", lossless);
            VERIFY (RGBtiff == lossless);
        }


        // IAP test

        ImageIOBase* iapdelegate;
        iapdelegate = ImageIODelegateList::gOnly().getDelegate ("iap");
        VERIFY (iapdelegate != 0);
        if (iapdelegate) {
            iapdelegate->write ("iap.iap", RGBtiff);

            Image<RGB> rgbIAP = iapdelegate->readRGB ("iap.iap");
            if (delegate)
                delegate->write ("iap.jpg", rgbIAP);
        }

    }


    UTFUNC(jpeg_info)
    {
        setDescription ("jpg info");

        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("jpg");
        VERIFY (delegate != 0);

        if (delegate) {
            VERIFY (delegate->info ("nonexistent.jpg").isDelegate == false);
            VERIFY (delegate->info ("iap.iap").isDelegate == false);
            VERIFY (delegate->info ("tif.tif").isDelegate == false);
            DelegateInfo info = delegate->info ("test.jpg");
            VERIFY (info.isDelegate == true);
            VERIFY (info.boundary.x0() == 0);
            VERIFY (info.boundary.y0() == 0);
            std::cout << "width = " << info.boundary.width() << ", height = " << info.boundary.height() << std::endl;
            VERIFY (info.boundary.width() > 0);
            VERIFY (info.boundary.height() > 0);
            VERIFY (info.planes == 3);
            VERIFY (info.bytesPerPixel == 3);
        }
    }

    UTFUNC(jpeg_read)
    {
        setDescription ("jpg read");


        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("jpg");
        VERIFY (delegate != 0);

        if (delegate) {
            Image<RGB> rgb = delegate->readRGB ("nonexistent.jpg");
            VERIFY (rgb == rgb.sNull);
            rgb = delegate->readRGB ("iap.iap");
            VERIFY (rgb == rgb.sNull);
            rgb = delegate->readRGB ("tif.tif");
            VERIFY (rgb == rgb.sNull);

            rgb = delegate->readRGB ("test.jpg");
            VERIFY (rgb != rgb.sNull);
            VERIFY (rgb.x0() == 0);
            VERIFY (rgb.y0() == 0);
            VERIFY (rgb.width() > 0);
            VERIFY (rgb.height() > 0);

            Image<RGB> rgb2;
            delegate->read ("test.jpg", rgb2);
            VERIFY (rgb == rgb2);

            Image<Pel8> byte1;
            delegate->read ("test.jpg", byte1);
            delegate->write ("output-byte.jpg", byte1);

            VERIFY (rgb.boundary() == byte1.boundary());

            Image<Pel32s> long1;
            delegate->read ("test.jpg", long1);
            VERIFY (rgb.boundary() == long1.boundary());

            // This will output as an rgb
            delegate->write ("test-long.jpg", long1);
        }
    }


    UTFUNC(tiff_info)
    {
        setDescription ("tif info");

        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("tif");
        VERIFY (delegate != 0);

        if (delegate) {
            VERIFY (delegate->info ("nonexistent.tif").isDelegate == false);
            VERIFY (delegate->info ("iap.iap").isDelegate == false);
            VERIFY (delegate->info ("test.jpg").isDelegate == false);
            DelegateInfo info = delegate->info ("tif.tif");
            VERIFY (info.isDelegate == true);
            VERIFY (info.boundary.x0() == 0);
            VERIFY (info.boundary.y0() == 0);
            std::cout << "width = " << info.boundary.width() << ", height = " << info.boundary.height() << std::endl;
            VERIFY (info.boundary.width() > 0);
            VERIFY (info.boundary.height() > 0);
            VERIFY (info.planes == 3);
            VERIFY (info.bytesPerPixel == 3);
        }
    }

    UTFUNC(tiff_read)
    {
        setDescription ("tif read");


        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("tif");
        VERIFY (delegate != 0);

        if (delegate) {
            Image<RGB> rgb = delegate->readRGB ("nonexistent.tif");
            VERIFY (rgb == rgb.sNull);
            rgb = delegate->readRGB ("iap.iap");
            VERIFY (rgb == rgb.sNull);
            rgb = delegate->readRGB ("test.jpg");
            VERIFY (rgb == rgb.sNull);

            rgb = delegate->readRGB ("tif.tif");
            VERIFY (rgb != rgb.sNull);
            VERIFY (rgb.x0() == 0);
            VERIFY (rgb.y0() == 0);
            VERIFY (rgb.width() > 0);
            VERIFY (rgb.height() > 0);

            Image<RGB> rgb2;
            delegate->read ("tif.tif", rgb2);
            VERIFY (rgb == rgb2);

            Image<Pel8> byte1;
            delegate->read ("tif.tif", byte1);
            delegate->write ("tif-byte.tif", byte1);

            VERIFY (rgb.boundary() == byte1.boundary());

            Image<Pel32s> long1;
            delegate->read ("tif.tif", long1);
            VERIFY (rgb.boundary() == long1.boundary());
        }
    }


    UTFUNC(iap_info)
    {
        setDescription ("iap info");

        ImageIOBase* delegate;
        delegate = ImageIODelegateList::gOnly().getDelegate ("iap");
        VERIFY (delegate != 0);

        if (delegate) {
            VERIFY (delegate->info ("nonexistent.iap").isDelegate == false);
            VERIFY (delegate->info ("test.jpg").isDelegate == false);
            VERIFY (delegate->info ("tif.tif").isDelegate == false);
            DelegateInfo info = delegate->info ("iap.iap");
            VERIFY (info.isDelegate == true);
            VERIFY (info.boundary.x0() == 0);
            VERIFY (info.boundary.y0() == 0);
            std::cout << "width = " << info.boundary.width() << ", height = " << info.boundary.height() << std::endl;
            VERIFY (info.boundary.width() > 0);
            VERIFY (info.boundary.height() > 0);
            VERIFY (info.planes == 3);
            VERIFY (info.bytesPerPixel == 3);
        }
    }
}